package tum0r.webengine.main

import tum0r.webengine.annotations.scan.ScanAnnotations
import tum0r.webengine.config.ApplicationConfig
import tum0r.webengine.config.DatabaseConfig
import tum0r.webengine.enums.EGenerateType
import tum0r.webengine.enums.ERequestMethod
import tum0r.webengine.enums.database.ETableFieldType
import tum0r.webengine.extension.*
import tum0r.webengine.models.core.EngineFile
import tum0r.webengine.models.database.DatabaseConnect
import tum0r.webengine.models.utils.CSV
import java.io.File
import java.lang.reflect.Field

/**
 * 说明: 框架代码生成
 *
 * 创建者: tum0r
 *
 * 时间: 2021/11/8 12:18
 */
class GenerateCode {
    companion object {
        /**
         * 生成数据库表字段的枚举类文件，文件名_Emus.kt
         */
        private fun generateEnum(targetPath: String, packageName: String?) {
            if (ApplicationConfig.TABLE_MAPPINGS.size == 0) return
            File(targetPath).createDir()

            // 枚举文件结构
            val enumContent = StringBuilder()
            enumContent.appendLine("""
            ${if (packageName.isNotNullOrBlank()) "package $packageName" else ""}

            import tum0r.webengine.extension.getAllEnumValue
            """.trimIndent()).appendLine()
            for (table in ApplicationConfig.TABLE_MAPPINGS) {
                val enumName = "E${table.tableName}"
                // 枚举类结构
                val temp = StringBuilder()
                for (field in table.fields)
                    if (field.COLUMN_NAME != null)
                        temp.append("${field.COLUMN_NAME!!}, ")

                enumContent.appendLine("""
                /**
                 * @see[tum0r.run.JavaMain]
                 */
                enum class $enumName {
                    ${temp.delete(temp.length - 2, temp.length)};
                
                    companion object {
                        /**
                         * 获取所有枚举类型
                         *
                         * @param[exceptFields] 排序的枚举类型
                         */
                        @JvmStatic
                        fun getAll(vararg exceptFields: $enumName) = getAllEnumValue(*exceptFields)
                    }
                }
                """.trimIndent()).appendLine()
            }
            File(targetPath + File.separator + "_Enums.kt").writeText(enumContent.toString())
        }

        private fun generateDatabase(database: DatabaseConnect, index: Int): String {
            val databaseName = database.name
            // 初始化代码
            val result = StringBuilder()

            // 按表的增删查改
            if (database.createTable) {
                for (table in ApplicationConfig.TABLE_MAPPINGS) {
                    // 数据表字段的数量
                    val columnSize = table.fields.size - 1
                    // 数据表名
                    val tableName = table.tableName
                    // 数据表的枚举名
                    val enumName = "E$tableName"
                    // 数据表类
                    val className = table.className
                    // 有索引的字段
                    val indexField = LinkedHashMap<String, Field>()
                    // 主键字段
                    var primaryKeyFieldSize = 0
                    // 外键字段
                    val foreignKeyFields = ArrayList<Field>()
                    // 所有字段名
                    val allFieldsName = StringBuilder()
                    // 自增主键名
                    var autoIncrement = ""
                    // 所有主键名
                    val keyName = StringBuilder()
                    // 所有主键名和类型
                    val keyNameAndType = StringBuilder()
                    // 主键的WHERE参数
                    val where = StringBuilder()

                    for (field in table.fields) {
                        allFieldsName.append("`${field.COLUMN_NAME}`, ")
                        if (field.tableField == null) continue
                        val columnName = field.COLUMN_NAME!!
                        val columnField = field.field!!
                        when (field.tableField!!.fieldType) {
                            ETableFieldType.AUTO_INCREMENT, ETableFieldType.PRIMARY_KEY -> {
                                keyName.append("$columnName, ")
                                keyNameAndType.append("$columnName: ${columnField.type.canonicalName}, ")
                                where.append("`$columnName`=@p$primaryKeyFieldSize AND ")
                                primaryKeyFieldSize++
                                if (field.tableField!!.fieldType == ETableFieldType.AUTO_INCREMENT)
                                    autoIncrement = columnName
                            }
                            ETableFieldType.FOREIGN_KEY -> foreignKeyFields.add(columnField)
                            else -> indexField[columnName] = columnField
                        }
                    }
                    allFieldsName.delete(allFieldsName.length - 2, allFieldsName.length)
                    keyName.delete(keyName.length - 2, keyName.length)
                    keyNameAndType.delete(keyNameAndType.length - 2, keyNameAndType.length)
                    where.delete(where.length - 5, where.length)

                    val tableOperator = StringBuilder()

                    // region 插入

                    // region getInsertSQL
                    tableOperator.appendLine("""
                    /**
                     * 获取插入数据库的SQL命令
                     */
                    fun getInsertSQL(command: StringBuilder, parameters: ArrayList<Any?>, target: ${className}) {
                        command.append("INSERT INTO `$tableName`($allFieldsName) VALUES(")
                        for (i in 0..$columnSize) {
                            command.append("@p").append(parameters.size + i)
                            if (i != 1) command.append(", ")
                        }
                        command.appendLine(");")
                    """.trimIndent())
                    for (field in table.fields)
                        tableOperator.appendLine("    parameters.add(target.${field.COLUMN_NAME})")
                    tableOperator.appendLine("}").appendLine()
                    // endregion

                    // region insert
                    tableOperator.appendLine("""
                    /**
                     * 插入到数据库
                     */
                    fun insert(target: $className): Int {
                        val command = StringBuilder()
                        val parameters = ArrayList<Any?>(${table.fields.size})
                        getInsertSQL(command, parameters, target)
                        val result = sql.update(command.toString(), *parameters.toArray())
                    """.trimIndent())
                    if (autoIncrement.isNotBlank())
                        tableOperator.appendLine("    target.$autoIncrement = sql.getGeneratedKeys()[0] as Int")
                    tableOperator.appendLine("    return result")
                    tableOperator.appendLine("}").appendLine()
                    // endregion

                    // endregion

                    // region 删除

                    // region deleteByWhere
                    tableOperator.appendLine("""
                    /**
                     * 按where删除
                     */
                    fun delete(where: String, vararg parameters: Any?): Boolean {
                        return if (where.isBlank()) false else sql.update("DELETE FROM `$tableName` WHERE ${'$'}where", *parameters) > 0
                    }
                    """.trimIndent()).appendLine()
                    // endregion

                    // region deleteByPrimaryKey
                    if (primaryKeyFieldSize != 0) {
                        tableOperator.appendLine("""
                    /**
                     * 按主键删除
                     */
                     fun deleteBy${keyName.toString().replace(", ", "_")}($keyNameAndType) = delete("$where", $keyName)
                        """.trimIndent()).appendLine()
                    }
                    // endregion

                    // endregion

                    // region 更新

                    // region getUpdateSQL
                    tableOperator.appendLine("""
                    /**
                     * 获取插入数据的SQL命令
                     */
                    fun getUpdateSQL(command: StringBuilder, parameters: ArrayList<Any?>, where: String, target: ${className}, vararg columns: $enumName) {
                        val targetColumns = if (columns.isEmpty()) $enumName.getAllArray() else columns
                        val size = targetColumns.size - 1
                        val commandTemp = StringBuilder()
                        commandTemp.append("UPDATE `$tableName` SET ")
                        for (i in 0..size) {
                            commandTemp.append("`${'$'}{targetColumns[i].name}`=@p${'$'}{i + parameters.size}")
                            if (i != size) commandTemp.append(", ")
                        }
                        commandTemp.appendLine("${'$'}{if (where.isNotBlank()) " WHERE ${'$'}where" else ""};")
                        command.append(commandTemp)
                    """.trimIndent())
                    tableOperator.appendLine("}").appendLine()
                    // endregion

                    // region update
                    tableOperator.appendLine("""
                    /**
                     * 更新数据库
                     *
                     * @return 返回更新的行数
                     */
                    fun update(columns: Array<$enumName>?, target: ${className}, where: String?, vararg parameters: Any?): Int {
                        val command = StringBuilder()
                        val parameters = ArrayList<Any?>()
                        getUpdateSQL(command, parameters, if (where.isNullOrBlank()) "$where" else where, target, *(if (columns == null || columns.isEmpty()) $enumName.getAllArray() else columns))
                        return sql.update(command.toString(), *parameters.toArray())
                    }
                    """.trimIndent()).appendLine()
                    // endregion

                    // endregion

                    // region 查找

                    // region exist
                    tableOperator.appendLine("""
                    /**
                     * 按where查找是否存在
                     */
                    fun exist(where: String, vararg parameters: Any?): Boolean = sql.selectValue("SELECT EXISTS(SELECT 1 FROM `$tableName`${'$'}{if (where.isNotBlank()) " WHERE ${'$'}where" else ""})", *parameters) ?: false
                    """.trimIndent()).appendLine()
                    // endregion

                    // region 按主键查找是否存在
                    if (primaryKeyFieldSize != 0) {
                        tableOperator.appendLine("""
                    /**
                     * 按主键查找是否存在
                     */
                     fun exist($keyNameAndType): Boolean = exist("$where", $keyName)
                        """.trimIndent()).appendLine()
                    }
                    // endregion

                    // region select
                    tableOperator.appendLine("""
                    /**
                     * 查找
                     */
                    fun select(columns: Array<$enumName>?, where: String, vararg parameters: Any?): ArrayList<$className> {
                        val selectColumns = StringBuilder()
                        if (columns == null || columns.isEmpty()) selectColumns.append("*")
                        else {
                            for (column in columns)
                                selectColumns.append("${'$'}{column.name}, ")
                            selectColumns.delete(selectColumns.length - 2, selectColumns.length)
                        }
                        return sql.selectObjects("SELECT ${'$'}selectColumns FROM `$tableName`${'$'}{if (where.isNotBlank()) " WHERE ${'$'}where" else " "}", *parameters)
                    }
                    """.trimIndent()).appendLine()
                    // endregion

                    // region selectByPrimaryKey
                    if (primaryKeyFieldSize != 0) {
                        tableOperator.appendLine("""
                        /**
                         * 按主键查找
                        */
                        fun selectBy${keyName.toString().replace(", ", "_")}($keyNameAndType, columns: Array<$enumName>?): $className? = select(columns, "$where", $keyName).getOrNull(0)
                        """.trimIndent()).appendLine()
                    }
                    // endregion

                    // region selectByIndex
                    for (indexKey in indexField) {
                        tableOperator.appendLine("""
                            /**
                             * 按索引 ${indexKey.key} 查找
                             */
                            fun selectBy${indexKey.key}(${indexKey.key}: ${indexKey.value.type.canonicalName}, columns: Array<$enumName>?): ArrayList<$className> = select(columns, "`${indexKey.key}`=@p0", ${indexKey.key})
                            """.trimIndent()).appendLine()
                    }
                    // endregion

                    // region selectJoin
//                    if (foreignKeyFields.size != 0) {
//                        tableOperator.appendLine("""
//                        /**
//                         * 连接查询
//                        */
//                        """.trimIndent()).appendLine()
//                    }
                    // endregion

                    // endregion

                    result.appendLine("""
                        @JvmField
                        val _$tableName = $tableName()
                        
                        class $tableName {
                            $tableOperator
                        }
                    """.trimIndent())
                }
            }
            return """
    class $databaseName {
        private val sql: SQL = SQLFactory.getSQL(DatabaseConfig.DATABASE_CONNECT_INFO[$index])

        init {
            try {
                if (sql.open()) {
                    "数据库 $databaseName 连接成功".infoLog()
                    if (BaseConfig.isState(EConfigType.INIT_DATABASE)) {
                        sql.initDatabase("${database.databaseName}")
                        "数据库 $databaseName 初始化完成".infoLog()
                    }
                } else "数据库 $databaseName 连接失败".errorLog()
            } catch (e: Exception) {
                "数据库 $databaseName 连接崩溃".errorLog()
                e.errorLog(true)
            }
        }

        /**
         * 执行SQL语句操作数据库
         */
        @JvmField
        val _DAO: DAO = DAO(sql)
        
        /**
         * 执行多条数据库语句
         *
         * @param[command] 执行的多条SQL语句字符串
         * @param[parameters]  执行的多条SQL语句的参数
         */
        fun executeMultiSQL(command: StringBuilder, parameters: ArrayList<Any?>): Int = if (command.isEmpty()) 0 else sql.update(command.toString(), *parameters.toArray())

        /**
         * 执行多条数据库语句
         *
         * @param[getSQL] 执行的多条SQL语句拼接方法
         */
        fun executeMultiSQL(getSQL: (StringBuilder, ArrayList<Any?>) -> Unit): Int {
            val command = StringBuilder()
            val parameters = ArrayList<Any?>()
            getSQL(command, parameters)
            return executeMultiSQL(command, parameters)
        }
        
        ${if (result.isNotEmpty()) "${System.lineSeparator()}$result" else ""}
    }
            """.trimIndent()
        }

        private fun generateDatabase(targetPath: String, packageName: String?) {
            // 生成数据库操作类前强制重新生成表字段的枚举类
            generateEnum(targetPath, packageName)

            // 生成数据库操作类
            val operator = StringBuilder()
            val databaseOperator = StringBuilder()
            for ((index, database) in DatabaseConfig.DATABASE_CONNECT_INFO.withIndex()) {
                databaseOperator.appendLine(generateDatabase(database, index))
                operator.appendLine("""
                    @JvmField
                    val _${database.name} = ${database.name}()
                """.trimIndent())
            }

            File(targetPath + File.separator + "_DB.kt").writeText("""
                ${if (packageName.isNotNullOrBlank()) "package $packageName" else ""}

                import tum0r.webengine.config.BaseConfig
                import tum0r.webengine.config.DatabaseConfig
                import tum0r.webengine.database.SQLFactory
                import tum0r.webengine.database.sql.MySQL
                import tum0r.webengine.database.sql.SQL
                import tum0r.webengine.enums.EConfigType
                import tum0r.webengine.extension.errorLog
                import tum0r.webengine.extension.infoLog
                import tum0r.webengine.models.database.PageModel

                /**
                 * 数据库操作
                 */
                class _DB {
                    companion object {
                        $operator
                    }

                    class DAO(private val sql: SQL) {
                        /**
                         * 更新数据库（包括增、删、改）
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         *
                         * @return 返回更新的条数
                         */
                        fun update(command: String, vararg parameters: Any?): Int = sql.update(command, *parameters)

                        /**
                         * 查询数据库，并以值集合的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        fun <T> selectValues(targetClass: Class<T>, command: String, vararg parameters: Any?): ArrayList<T> = sql.selectValues(targetClass, command, *parameters)

                        /**
                         * 查询数据库，并以值集合的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         *
                         * @return 查询不到返回null
                         */
                        fun <T> selectValue(targetClass: Class<T>, command: String, vararg parameters: Any?): T? = selectValues(targetClass, command, *parameters).getOrNull(0)

                        /**
                         * 查询数据库，并以强类型对象集合的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        fun <T> selectObjects(targetClass: Class<T>, command: String, vararg parameters: Any?): ArrayList<T> = sql.selectObjects(targetClass, command, *parameters)

                        /**
                         * 查询数据库，并以强类型对象集合的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         *
                         * @return 查询不到返回null
                         */
                        fun <T> selectObject(targetClass: Class<T>, command: String, vararg parameters: Any?): T? = selectObjects(targetClass, command, *parameters).getOrNull(0)

                        /**
                         * 查询数据库，并以分页对象的形式返回数据
                         *
                         * @param[targetClass] 强类型对象的类型
                         * @param[index] 查询的页号，从0开始
                         * @param[pageSize] 每页的数量
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        @JvmOverloads
                        fun <T> selectPage(targetClass: Class<T>, index: Int, pageSize: Int = 15, command: String, vararg parameters: Any?): PageModel<T> {
                            return when (sql) {
                                is MySQL -> sql.selectPage(targetClass, index, pageSize, command, *parameters)
                                else -> PageModel()
                            }
                        }

                        /**
                         * 查询数据库，并以值集合的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectValues(targetClass: Class<T>, command: String, vararg parameters: Any?)"))
                        fun <T> selectValuesUnsafe(targetClass: Class<T>, command: String) = sql.selectValuesUnsafe(targetClass, command)

                        /**
                         * 查询数据库，并以值的形式返回数据
                         *
                         * @param[targetClass] 值的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         *
                         * @return 查询不到返回null
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectValue(targetClass: Class<T>, command: String, vararg parameters: Any?)"))
                        fun <T> selectValueUnsafe(targetClass: Class<T>, command: String) = selectValuesUnsafe(targetClass, command).getOrNull(0)

                        /**
                         * 查询数据库，并以强类型对象集合的形式返回数据
                         *
                         * @param[targetClass] 强类型对象的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectObjects(targetClass: Class<T>, command: String, vararg parameters: Any?)"))
                        fun <T> selectObjectsUnsafe(targetClass: Class<T>, command: String) = sql.selectObjectsUnsafe(targetClass, command)

                        /**
                         * 查询数据库，并以强类型对象的形式返回数据
                         *
                         * @param[targetClass] 强类型对象的类型
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         *
                         * @return 查询不到返回null
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectObject(targetClass: Class<T>, command: String, vararg parameters: Any?)"))
                        fun <T> selectObjectUnsafe(targetClass: Class<T>, command: String) = selectObjectsUnsafe(targetClass, command).getOrNull(0)

                        /**
                         * 查询数据库，并以值集合的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        inline fun <reified T> selectValues(command: String, vararg parameters: Any?): ArrayList<T> = selectValues(T::class.java, command, *parameters)

                        /**
                         * 查询数据库，并以值的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         *
                         * @return 查询不到返回null
                         */
                        inline fun <reified T> selectValue(command: String, vararg parameters: Any?): T? = selectValue(T::class.java, command, *parameters)

                        /**
                         * 查询数据库，并以强类型对象集合的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        inline fun <reified T> selectObjects(command: String, vararg parameters: Any?): ArrayList<T> = selectObjects(T::class.java, command, *parameters)

                        /**
                         * 查询数据库，并以强类型对象的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         *
                         * @return 查询不到返回null
                         */
                        inline fun <reified T> selectObject(command: String, vararg parameters: Any?): T? = selectObject(T::class.java, command, *parameters)

                        /**
                         * 查询数据库，并以分页对象的形式返回数据
                         *
                         * @param[index] 查询的页号，从0开始
                         * @param[pageSize] 每页的数量
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         * @param[parameters] 命令的参数
                         */
                        @JvmOverloads
                        inline fun <reified T> selectPage(index: Int, pageSize: Int = 15, command: String, vararg parameters: Any?): PageModel<T> = selectPage(T::class.java, index, pageSize, command, *parameters)

                        /**
                         * 查询数据库，并以值集合的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectValues(command: String, vararg parameters: Any?)"))
                        inline fun <reified T> selectValuesUnsafe(command: String) = selectValuesUnsafe(T::class.java, command)

                        /**
                         * 查询数据库，并以值的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         *
                         * @return 查询不到返回null
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectValue(command: String, vararg parameters: Any?)"))
                        inline fun <reified T> selectValueUnsafe(command: String) = selectValueUnsafe(T::class.java, command)

                        /**
                         * 查询数据库，并以强类型对象集合的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectObjects(command: String, vararg parameters: Any?)"))
                        inline fun <reified T> selectObjectsUnsafe(command: String) = selectObjectsUnsafe(T::class.java, command)

                        /**
                         * 查询数据库，并以强类型对象的形式返回数据
                         *
                         * @param[command] SQL语句，语句中参数占位符为 @p 或 @P 然后加数字，例如 @p0, @P1
                         *
                         * @return 查询不到返回null
                         */
                        @Deprecated("此方法不安全，会引起SQL注入攻击", ReplaceWith("selectObject(command: String, vararg parameters: Any?)"))
                        inline fun <reified T> selectObjectUnsafe(command: String) = selectObjectUnsafe(T::class.java, command)
                    }
                    
                    $databaseOperator
                }
            """.trimIndent())
        }

        private fun generateJavaScript(targetPath: String) {
            val dir = File(targetPath)
            dir.createDir()
            val path = dir.absolutePath + File.separator

            val content = StringBuilder()
            var oldPath = ""
            for (mapping in ApplicationConfig.SERVER_MAPPINGS) {
                if (mapping.index < 0) continue
                val mappingPath = mapping.path.substring(0, mapping.path.lastIndexOf("/")).replace("/", "_")
                val methodName = mapping.path.substring(mapping.path.lastIndexOf("/") + 1)
                if (oldPath != mappingPath) {
                    if (content.isNotEmpty()) {
                        File("$path$oldPath.js").writeText(content.toString())
                        content.clear()
                    }
                    oldPath = mappingPath
                }
                if (content.isEmpty()) {
                    content.appendLine(
                        """
                const $mappingPath = {};
                $mappingPath.base_url = ""
                $mappingPath.action_url = "/${mapping.path.substring(1, mapping.path.lastIndexOf("/"))}"
                $mappingPath.errorMessage = null
                $mappingPath.onerror = null

                $mappingPath.send = function(url, callback) {
                    let request = new XMLHttpRequest();
                    request.onerror = $mappingPath.onerror;
                    request.onreadystatechange = function() {
                        if (request.readyState === 4) {
                            let result = null;
                            if (request.status === 200) {
                                result = request.responseText ? request.responseText : null;
                                if (result.indexOf('errCode') != -1) {
                                    if (security_flag.errorMessage) security_flag.errorMessage(result);
                                    else console.error(result);
                                } else if (callback) callback(result);
                            } else {
                                console.error(request);
                            }
                        }
                    }
                    request.responseType = "text";
                    return request
                }

                $mappingPath.sendGET = function(url, data, callback) {
                    $mappingPath.send(url, callback).open("GET", $mappingPath.base_url + $mappingPath.action_url + url + "?" + data, true);
                }

                $mappingPath.sendPOST = function(url, data, callback) {
                    let request = $mappingPath.send(url, callback)
                    request.open("POST", $mappingPath.base_url + $mappingPath.action_url + url, true);
                    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
                    request.send(data);
                }
            """.trimIndent()
                    )
                }
                val genericClass = mapping.function!!.genericClass(mapping.function.parameterCount - 1).getOrNull(0)
                if (genericClass == null || genericClass == File::class.java || genericClass == EngineFile::class.java || genericClass == CSV::class.java || genericClass == ByteArray::class.java)
                    continue
                content.appendLine().append("$mappingPath.$methodName = function(")
                for (parameterName in ApplicationConfig.SERVER_METHOD_PARAMETERS_MAPPING[mapping.functionIndex].parametersName)
                    content.append("$parameterName, ")
                content.deleteRange(content.length - 2, content.length)
                content.appendLine(") {")
                content.appendLine("    let data = [];")
                val size = ApplicationConfig.SERVER_METHOD_PARAMETERS_MAPPING[mapping.functionIndex].parametersName.size - 1
                for (i in 0 until size) {
                    val parameterName = ApplicationConfig.SERVER_METHOD_PARAMETERS_MAPPING[mapping.functionIndex].parametersName[i]
                    content.appendLine("    data.push(\"$parameterName=\" + $parameterName);")
                }
                if (mapping.method == ERequestMethod.GET)
                    content.appendLine("    $mappingPath.sendGET(\"/$methodName\", data.join(\"&\"), ${ApplicationConfig.SERVER_METHOD_PARAMETERS_MAPPING[mapping.functionIndex].parametersName.last()});")
                else
                    content.appendLine("    $mappingPath.sendPOST(\"/$methodName\", data.join(\"&\"), ${ApplicationConfig.SERVER_METHOD_PARAMETERS_MAPPING[mapping.functionIndex].parametersName.last()});")
                content.appendLine("}")
            }
            if (content.isNotEmpty()) File("$path$oldPath.js").writeText(content.toString())
        }

        private fun generateKotlin(targetPath: String, packageName: String?) {
        }

        private fun generateJava(targetPath: String, packageName: String?) {
        }

        /**
         * 生成代码
         *
         * @param[type] 生成代码类型
         * @param[targetPath] 生成代码路径
         * @param[packageName] 生成代码包名
         */
        @JvmStatic
        fun generateCode(type: EGenerateType, targetPath: String, packageName: String?) {
            banLogFile()
            val scanAnnotations = ScanAnnotations()
            scanAnnotations.scanTables()
            scanAnnotations.scanServers()
            when (type) {
                EGenerateType.Database -> generateDatabase(targetPath, packageName)
                EGenerateType.JavaScript -> generateJavaScript(targetPath)
                EGenerateType.Kotlin -> generateKotlin(targetPath, packageName)
                EGenerateType.Java -> generateJava(targetPath, packageName)
            }
            "生成代码完成".infoLog()
        }

        @JvmStatic
        fun generateCode(typeName: String, targetPath: String, packageName: String) = generateCode(parseEnum<EGenerateType>(typeName), targetPath, packageName)
    }
}